Coverage Report

Created: 2024-12-26 12:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\gen\rust\util.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::message::{Field, FieldType, Message};
30
use crate::compiler::structure::FixedFieldType;
31
use crate::compiler::util::types::TypeMapper;
32
use crate::gen::base::map::TypePathMapper;
33
use crate::gen::template::Template;
34
use crate::model::protocol::Endianness;
35
use itertools::Itertools;
36
use std::borrow::Cow;
37
38
macro_rules! gen_value_type {
39
    ($prefix: literal, $ty: expr, $suffix: literal) => {
40
        match $ty {
41
            FixedFieldType::Int8 => concat!($prefix, "i8", $suffix),
42
            FixedFieldType::Int16 => concat!($prefix, "i16", $suffix),
43
            FixedFieldType::Int32 => concat!($prefix, "i32", $suffix),
44
            FixedFieldType::Int64 => concat!($prefix, "i64", $suffix),
45
            FixedFieldType::UInt8 => concat!($prefix, "u8", $suffix),
46
            FixedFieldType::UInt16 => concat!($prefix, "u16", $suffix),
47
            FixedFieldType::UInt32 => concat!($prefix, "u32", $suffix),
48
            FixedFieldType::UInt64 => concat!($prefix, "u64", $suffix),
49
            FixedFieldType::Float32 => concat!($prefix, "f32", $suffix),
50
            FixedFieldType::Float64 => concat!($prefix, "f64", $suffix),
51
            FixedFieldType::Bool => concat!($prefix, "bool", $suffix),
52
        }
53
    };
54
}
55
56
pub struct Generic<'a> {
57
    pub name: Cow<'a, str>,
58
    pub default: Option<Cow<'a, str>>,
59
}
60
61
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
62
pub enum Lifetime {
63
    None,
64
    Anonymous,
65
    Named
66
}
67
68
pub struct Generics<T> {
69
    lifetime: Lifetime,
70
    data: T,
71
}
72
73
impl<T> Generics<T> {
74
107
    pub fn new(lifetime: Lifetime, data: T) -> Self {
75
107
        Self {
76
107
            lifetime,
77
107
            data
78
107
        }
79
107
    }
80
}
81
82
107
fn _to_string<'a>(mut generics: impl Iterator<Item=Cow<'a, str>>, lifetime: Lifetime) -> Cow<'a, str>{
83
107
    if let Some(
value20
) = generics.next() {
  Branch (83:12): [True: 16, False: 60]
  Branch (83:12): [True: 4, False: 27]
  Branch (83:12): [Folded - Ignored]
84
20
        let str = generics.join(", ");
85
20
        match (str.is_empty(), lifetime) {
86
4
            (true, Lifetime::None) => format!("<{}>", value).into(),
87
0
            (false, Lifetime::None) => format!("<{}, {}>", value, str).into(),
88
12
            (true, Lifetime::Named) => format!("<'a, {}>", value).into(),
89
0
            (false, Lifetime::Named) => format!("<'a, {}, {}>", value, str).into(),
90
4
            (true, Lifetime::Anonymous) => format!("<'_, {}>", value).into(),
91
0
            (false, Lifetime::Anonymous) => format!("<'_, {}, {}>", value, str).into(),
92
        }
93
87
    } else if lifetime == Lifetime::Named {
  Branch (93:15): [True: 29, False: 31]
  Branch (93:15): [True: 27, False: 0]
  Branch (93:15): [Folded - Ignored]
94
56
        Cow::Borrowed("<'a>")
95
31
    } else if lifetime == Lifetime::Anonymous {
  Branch (95:15): [True: 0, False: 31]
  Branch (95:15): [True: 0, False: 0]
  Branch (95:15): [Folded - Ignored]
96
0
        Cow::Borrowed("<'_>")
97
    } else {
98
31
        Cow::Borrowed("")
99
    }
100
107
}
101
102
impl<'a, T: Iterator<Item = Generic<'a>>> Generics<T> {
103
76
    pub fn into_string(self) -> Cow<'a, str> {
104
76
        let generics = self.data.map(|v| 
match &v.default16
{
105
0
            None => v.name,
106
16
            Some(_) => v.name,
107
76
        
}16
);
108
76
        _to_string(generics, self.lifetime)
109
76
    }
110
111
31
    pub fn into_string_with_defaults(self) -> Cow<'a, str> {
112
31
        let generics = self.data.map(|v| 
match &v.default4
{
113
0
            None => v.name,
114
4
            Some(v1) => format!("{}={}", v.name, v1).into(),
115
31
        
}4
);
116
31
        _to_string(generics, self.lifetime)
117
31
    }
118
}
119
120
pub struct RustUtils;
121
122
impl RustUtils {
123
107
    fn _gen_generics<'a, T: TypeMapper>(msg: &'a Message, type_path_map: &'a TypePathMapper<T>, lifetime: Lifetime) -> Generics<impl Iterator<Item = Generic<'a>>> {
124
209
        let unions = msg.fields.iter().filter_map(|v| match &v.ty {
125
20
            FieldType::Union(u) => Some(Generic {
126
20
                name: format!("T{}", v.name).into(),
127
20
                default: Some(format!("{}<'a>", type_path_map.get(&u.r)).into()),
128
20
            }),
129
189
            _ => None,
130
209
        });
131
107
        Generics::new(lifetime, unions)
132
107
    }
133
134
43
    pub fn get_generics_for_write<'a, T: TypeMapper>(
135
43
        msg: &'a Message,
136
43
        type_path_map: &'a TypePathMapper<T>,
137
43
        lifetime: Lifetime,
138
43
    ) -> Generics<impl Iterator<Item = Generic<'a>>> {
139
89
        let has_lifetime = msg.fields.iter().any(|v| {
140
89
            
matches!77
(v.ty, FieldType::Union(_))
141
89
        });
142
43
        Self::_gen_generics(msg, type_path_map, if has_lifetime { 
lifetime12
} else {
Lifetime::None31
})
  Branch (142:52): [True: 12, False: 31]
  Branch (142:52): [Folded - Ignored]
143
43
    }
144
145
64
    pub fn get_generics<'a, T: TypeMapper>(
146
64
        msg: &'a Message,
147
64
        type_path_map: &'a TypePathMapper<T>,
148
64
    ) -> Generics<impl Iterator<Item = Generic<'a>>> {
149
64
        let has_lifetime = msg.fields.iter().any(|v| {
150
0
            matches!(
151
64
                v.ty,
152
                FieldType::Ref(_)
153
                    | FieldType::Buffer
154
                    | FieldType::SizedBuffer(_)
155
                    | FieldType::FixedContainer(_)
156
                    | FieldType::Union(_)
157
                    | FieldType::Container(_)
158
                    | FieldType::SizedContainer(_)
159
                    | FieldType::Payload
160
            )
161
64
        });
162
64
        Self::_gen_generics(msg, type_path_map, if has_lifetime { Lifetime::Named } else { 
Lifetime::None0
})
  Branch (162:52): [True: 64, False: 0]
  Branch (162:52): [Folded - Ignored]
163
64
    }
164
}
165
166
impl crate::gen::base::structure::Utilities for RustUtils {
167
1.22k
    fn get_field_type(field_type: FixedFieldType) -> &'static str {
168
1.22k
        
gen_value_type!96
("", field_type, "")
169
1.22k
    }
170
171
200
    fn get_fragment_name(field: &crate::compiler::structure::Field) -> &'static str {
172
200
        let raw_field_type = field.ty.as_fixed().unwrap().bits_type;
173
200
        let raw_field_byte_size = raw_field_type.get_byte_size();
174
200
        match raw_field_byte_size != field.loc.byte_size {
175
12
            true => "unaligned",
176
188
            false => "aligned",
177
        }
178
200
    }
179
180
64
    fn get_bit_codec_inline(endianness: Endianness) -> &'static str {
181
64
        match endianness {
182
48
            Endianness::Little => "<bp3d_proto::codec::BitCodecLE as bp3d_proto::codec::BitCodec>",
183
16
            Endianness::Big => "<bp3d_proto::codec::BitCodecBE as bp3d_proto::codec::BitCodec>",
184
        }
185
64
    }
186
187
136
    fn get_byte_codec_inline(endianness: Endianness) -> &'static str {
188
136
        match endianness {
189
136
            Endianness::Little => "<bp3d_proto::codec::ByteCodecLE as bp3d_proto::codec::ByteCodec>",
190
0
            Endianness::Big => "<bp3d_proto::codec::ByteCodecBE as bp3d_proto::codec::ByteCodec>",
191
        }
192
136
    }
193
194
12
    fn get_byte_codec(endianness: Endianness) -> &'static str {
195
12
        match endianness {
196
12
            Endianness::Little => "bp3d_proto::codec::ByteCodecLE",
197
0
            Endianness::Big => "bp3d_proto::codec::ByteCodecBE",
198
        }
199
12
    }
200
}
201
202
impl crate::gen::base::message::Utilities for RustUtils {
203
139
    fn get_value_type(endianness: Endianness, ty: FixedFieldType) -> &'static str {
204
139
        match endianness {
205
139
            Endianness::Little => 
gen_value_type!0
("bp3d_proto::message::util::ValueLE<", ty, ">"),
206
0
            Endianness::Big => gen_value_type!("bp3d_proto::message::util::ValueBE<", ty, ">"),
207
        }
208
139
    }
209
210
10
    fn get_value_type_inline(endianness: Endianness, ty: FixedFieldType) -> &'static str {
211
10
        match endianness {
212
10
            Endianness::Little => 
gen_value_type!0
("bp3d_proto::message::util::ValueLE::<", ty, ">"),
213
0
            Endianness::Big => gen_value_type!("bp3d_proto::message::util::ValueBE::<", ty, ">"),
214
        }
215
10
    }
216
217
10
    fn gen_struct_ref_type(type_name: &str) -> String {
218
10
        format!("{}<&'a [u8]>", type_name)
219
10
    }
220
221
3
    fn gen_message_ref_type(type_name: &str) -> String {
222
3
        format!("{}<'a>", type_name)
223
3
    }
224
}
225
226
154
pub fn gen_where_clause<T: TypeMapper>(
227
154
    template: &Template,
228
154
    field: &Field,
229
154
    type_path_map: &TypePathMapper<T>,
230
154
    function: &str,
231
154
) -> String {
232
154
    match &field.ty {
233
14
        FieldType::Union(v) => template
234
14
            .scope()
235
14
            .var("name", &field.name)
236
14
            .var("type_name", type_path_map.get(&v.r))
237
14
            .var("discriminant_type", type_path_map.get(&v.r.discriminant.root))
238
14
            .render(function, &["where"])
239
14
            .unwrap(),
240
140
        _ => "".into(),
241
    }
242
154
}